package biz

import (
	"context"
	"encoding/json"
	"fmt"
	"os"
	"time"
	"uwbwebapp/pkg/cache"
	"uwbwebapp/pkg/dao"
	"uwbwebapp/pkg/entities"
	"uwbwebapp/pkg/tools"

	"github.com/google/uuid"
)

// 计算平均每分钟游泳距离
func ComputeSwimmerUWBTerminalReport(swimmerId string, dateTime entities.BetweenDatetime) (entities.SwimmerUWBTerminalReport, error) {
	records, err := dao.EnumSwimmerUWBTerminalRecordsByDateScope(swimmerId, dateTime)
	var result entities.SwimmerUWBTerminalReport
	result.AverageMileage = 0.0
	result.Minutes = 0
	result.TotalMileage = 0.0
	if err != nil {
		fmt.Println("Failed to get swimmer records:", err)
		return result, err
	}

	// 计算 InFence 为 True 的数据
	var inFenceRecords []entities.SwimmerUWBTerminalRecord
	for _, record := range records {
		if record.InFence {
			inFenceRecords = append(inFenceRecords, record)
		}
	}

	// 计算 Mileage 总数
	totalMileage := 0.0
	for _, record := range inFenceRecords {
		totalMileage += record.Mileage
	}

	// 计算每分钟平均 Mileage
	duration := dateTime.EndDatetime.Sub(dateTime.BeginDatetime)
	result.Minutes = duration.Minutes()
	result.AverageMileage = totalMileage / result.Minutes

	return result, err
}

// 计算给定时间段的每日情况
func CalculateDailyStats(records []entities.SwimmerUWBTerminalRecord) map[string]float64 {
	dailyStats := make(map[string]float64)
	for _, record := range records {
		date := record.CreateDatetime.Format(tools.GOOGLE_DATETIME_FORMAT_NO_TIME)
		if _, ok := dailyStats[date]; !ok {
			dailyStats[date] = 0.0
		}
		dailyStats[date] += record.Mileage
	}
	return dailyStats
}

/*
将 UWB 终端记录写入缓存。

参数

- `uwb_infor`：指向UWBTerminalMQTTInformation结构体的指针。

- `inFence`：表示记录是否在围栏内的布尔值。

返回

- 错误，如果有的话。
*/
func WriteUWBTerminalRecord(uwb_infor *entities.UWBTerminalMQTTInformation, inFence bool) error {
	var err error
	var record entities.SwimmerUWBTerminalRecord
	record.X = uwb_infor.X
	record.Y = uwb_infor.Y
	record.Z = uwb_infor.Z
	record.InFence = inFence
	record.SwimmerID = uwb_infor.Properties.SwimmerId
	if record.Id == "" {
		record.Id = uuid.New().String()
	}
	record.CreateDatetime = time.Now()
	record.ModifyDatetime = record.CreateDatetime
	record.Creator = "uwb"
	record.Modifier = record.Creator
	record.Mileage = uwb_infor.Distance

	err = writeUWBTerminalRecordToCache(&record)
	return err
}

/*
- 描述：将UWB终端记录写入缓存。
- 参数：
  - `record`：指向SwimmerUWBTerminalRecord结构体的指针。

- 返回：错误，如果有的话。
*/
func writeUWBTerminalRecordToCache(record *entities.SwimmerUWBTerminalRecord) error {
	rctx := context.Background()
	key := fmt.Sprintf("UWB_record_%s_%s", record.SwimmerID, record.CreateDatetime.Format(tools.GOOGLE_DATETIME_FORMAT_NO_TIME))
	data, err := json.Marshal(record)
	if err == nil {
		cache.RedisDatabase.LPush(rctx, key, data)
	}
	return err
}

/*
- 描述：从Redis缓存中检索单个日期的UWB终端记录。
- 参数：
  - `swimmerId`：游泳者的ID。
  - `date`：要检索记录的日期。

- 返回：
  - `[]entities.SwimmerUWBTerminalRecord`：SwimmerUWBTerminalRecord结构体的切片。
  - `[]error`：错误的切片，如果有的话。
*/
func GetUWBTerminalSingleDateRecordsFromRedis(swimmerId string, date time.Time) ([]entities.SwimmerUWBTerminalRecord, []error) {
	var result []entities.SwimmerUWBTerminalRecord
	var errs []error
	rctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
	keys := fmt.Sprintf("UWB_record_%s_%s", swimmerId, date.Format(tools.GOOGLE_DATETIME_FORMAT_NO_TIME))
	defer cancel()
	strArrayRecords, err := cache.RedisDatabase.LRange(rctx, keys, 0, -1).Result()
	if err == nil {
		for _, strRecord := range strArrayRecords {
			var record entities.SwimmerUWBTerminalRecord
			ex := json.Unmarshal([]byte(strRecord), &record)
			if ex == nil {
				result = append(result, record)
			} else {
				errs = append(errs, ex)
			}
		}
	} else {
		errs = append(errs, err)
	}
	return result, errs
}

/*
- 描述：枚举给定游泳者和日期范围内的UWB终端记录。
- 参数：
  - `swimmerId`：游泳者的ID。
  - `date`：表示日期范围的BetweenDatetime结构体。

- 返回：
  - `map[string][]entities.SwimmerUWBTerminalRecord`：以日期字符串为键，以SwimmerUWBTerminalRecord结构体的切片为值的映射。
  - `[]error`：错误的切片，如果有的话。
*/
func EnumUWBTerminalRecordsFromCache(swimmerId string, date entities.BetweenDatetime) (map[string][]entities.SwimmerUWBTerminalRecord, []error) {
	var errs []error
	mapRecords := make(map[string][]entities.SwimmerUWBTerminalRecord)
	currentDate := date.BeginDatetime
	for currentDate.Before(date.EndDatetime) || currentDate.Equal(date.EndDatetime) {
		var exs []error

		mapRecords[currentDate.Format(tools.GOOGLE_DATETIME_FORMAT_NO_TIME)], exs = GetUWBTerminalSingleDateRecordsFromRedis(swimmerId, currentDate)
		errs = append(errs, fmt.Errorf("%v", exs))
	}
	return mapRecords, errs
}
func GetUWBTerminalSingleDateRecordsFromFile(swimmerId string, date time.Time) ([]entities.SwimmerUWBTerminalRecord, error) {
	var records []entities.SwimmerUWBTerminalRecord
	strCurrentDate := date.Format(tools.GOOGLE_DATETIME_FORMAT_NO_TIME)
	filePath := fmt.Sprintf("./uwbrecords/%s/%s", strCurrentDate, swimmerId)
	stat, err := os.Stat(filePath)
	if err == nil {
		// 证明文件存在
		var f *os.File
		f, err = os.OpenFile(filePath, os.O_RDONLY, 0666)
		if err == nil {
			byteContent := make([]byte, stat.Size())
			_, err = f.Read(byteContent)
			if err == nil {
				var tmp []entities.SwimmerUWBTerminalRecord
				err = json.Unmarshal(byteContent, &tmp)
				if err == nil {
					records = append(records, tmp...)
				}
			}
		}
		f.Close()
	}
	return records, err
}

// 生成游泳者运动报告通过UWB终端记录
func GenerateUWBTerminalRecordReport(swimmerId string, date entities.BetweenDatetime) ([]entities.SwimmerUWBTerminalRecordReport, error) {
	var reports []entities.SwimmerUWBTerminalRecordReport
	currentDate := date.BeginDatetime
	now := time.Now()
	var err error
	for currentDate.Before(date.EndDatetime) || currentDate.Equal(date.EndDatetime) {
		var records []entities.SwimmerUWBTerminalRecord
		strCurrentDate := currentDate.Format(tools.GOOGLE_DATETIME_FORMAT_NO_TIME)
		if strCurrentDate != now.Format(tools.GOOGLE_DATETIME_FORMAT_NO_TIME) {
			// 不是当天需要从文件记录中获取否则需要从缓存中获取。
			tmp, fe := GetUWBTerminalSingleDateRecordsFromFile(swimmerId, currentDate)
			if fe == nil {
				records = append(records, tmp...)
			}

		} else {
			tmp, re := GetUWBTerminalSingleDateRecordsFromRedis(swimmerId, currentDate)
			if re == nil {

				records = append(records, tmp...)
			}
		}
		// 生成报告
		var report entities.SwimmerUWBTerminalRecordReport
		report.Date = currentDate
		report.Mileage, report.Minute = ComputeSumMileageAndSumMinute(records)
		report.SwimmerId = swimmerId
		if report.Minute != 0 {
			report.MinuteSpeed = report.Mileage / report.Minute
		}
		if report.Mileage > 0 {
			reports = append(reports, report)
		}
		currentDate = currentDate.AddDate(0, 0, 1)
	}

	return reports, err
}

func ComputeSumMileageAndSumMinute(records []entities.SwimmerUWBTerminalRecord) (float64, float64) {
	var sumMileage, sumMinute float64
	var millisecond int64 = 0
	var pRecordDateTime time.Time
	for i, record := range records {
		// 这里很重要，只需要在游泳范围的记录才进行计算否则需要跳过
		if record.InFence {
			sumMileage += record.Mileage
			if i > 0 {
				tmp := pRecordDateTime.Sub(record.CreateDatetime).Milliseconds()
				if tmp < 1000*60*1 && tmp > 0 {
					// 间隔小于1分钟的纳入计算，避免长期停滞时计算平均值。
					millisecond += tmp
				}
			}
			pRecordDateTime = record.CreateDatetime
		}
	}
	second := float64(millisecond) / 1000
	sumMinute = second / 60
	return sumMileage, sumMinute
}
